package com.zhangfb95.crosschain.server.infra.model.service.dto;

import com.zhangfb95.crosschain.infra.exception.BusinessException;
import com.zhangfb95.crosschain.protocol.exc.response.ListChainPathExcRes;
import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhangfubing
 * @since 2023/12/5
 */
@Slf4j
public class ChainInfoHolder {

    private final Map<String, ChainInfo> chainPath2ChainInfoMap = new ConcurrentHashMap<>();
    private final Map<String, String> serverId2ServerUrlMap = new ConcurrentHashMap<>();

    public void updateChainInfo(String localServerId,
                                List<String> localChainPaths,
                                Map<String, ListChainPathExcRes> url2ResMap) {
        Set<String> canBeDeletedChainPaths = new HashSet<>(chainPath2ChainInfoMap.keySet());
        Set<String> canBeDeletedServerIds = new HashSet<>(serverId2ServerUrlMap.keySet());

        localChainPaths.forEach(localChainPath -> {
            ChainInfo chainInfo = new ChainInfo()
                    .setLocal(true)
                    .setChainPath(localChainPath)
                    .setServerId(localServerId)
                    .setServerUrl(null);
            chainPath2ChainInfoMap.put(localChainPath, chainInfo);
            canBeDeletedChainPaths.remove(localChainPath);
        });

        url2ResMap.forEach((url, res) -> {
            res.getChainPaths().forEach(remoteChainPath -> {
                ChainInfo chainInfo = new ChainInfo()
                        .setLocal(false)
                        .setChainPath(remoteChainPath)
                        .setServerId(res.getServerId())
                        .setServerUrl(url);
                chainPath2ChainInfoMap.put(remoteChainPath, chainInfo);
                canBeDeletedChainPaths.remove(remoteChainPath);
            });
            serverId2ServerUrlMap.put(res.getServerId(), url);
            canBeDeletedServerIds.remove(res.getServerId());
        });


        canBeDeletedChainPaths.forEach(chainPath2ChainInfoMap::remove);
        canBeDeletedServerIds.forEach(serverId2ServerUrlMap::remove);
        log.info("current chainPaths: {}", chainPath2ChainInfoMap.keySet());
    }

    public ChainInfo getChainInfo(String chainPath) {
        ChainInfo chainInfo = chainPath2ChainInfoMap.get(chainPath);
        if (chainInfo == null) {
            throw new BusinessException("chainInfo not find, chainPath=" + chainPath);
        }
        return chainInfo;
    }

    public String getServerUrl(String serverId) {
        String serverUrl = serverId2ServerUrlMap.get(serverId);
        if (serverUrl == null) {
            throw new BusinessException("serverUrl not find, serverId=" + serverId);
        }
        return serverUrl;
    }
}
